﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Schema;
using System.Collections;
using RadowCore.Models;

namespace RadowCore.Helpers
{
    /// <summary>
    /// This class implements the IlogParser interface to parse XML log file
    /// </summary>
    class XMLParser: ILogParser
    {
        bool Isvalid;
        bool StopLoop;
        public int workSize { set; get; }
        List<string> m_allRples;

        public List<string> AllRples
        {
            get { return m_allRples; }
            set { m_allRples = value; }
        }

        public XMLParser()
        {
            m_allRples = new List<string>();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public LogEntryCollection ParseLog(string filename)
        {
            //validate the xml file against XSD schema
            workSize = 0;
            XmlDocument logFile = new XmlDocument();
            logFile.Load(filename);

            XmlNamespaceManager nsmanager = new XmlNamespaceManager(logFile.NameTable);
            nsmanager.AddNamespace("m", "XSDMXML");
            
            LogEntryCollection collection = new LogEntryCollection();
            XmlNode root = logFile.DocumentElement;
            XmlNodeList allProcess = root.SelectNodes("./m:Process", nsmanager);
            foreach (XmlNode processNode in allProcess)
            {
                string processID = processNode.Attributes["id"].Value;

                XmlNodeList allProcessInstance = processNode.SelectNodes("./m:ProcessInstance", nsmanager);

                ProcessLogEntry currentProcess = new ProcessLogEntry();

                foreach (XmlNode processInstanceNode in allProcessInstance)
                {
                    workSize++;
                    string processInstanceID = processInstanceNode.Attributes["id"].Value;

                    XmlNodeList allAuditTrailEntry = processInstanceNode.SelectNodes("./m:AuditTrailEntry", nsmanager);
                    
                    TraceLogEntry currentTrace = new TraceLogEntry();
                    
                    foreach (XmlNode auditTrailEntryNode in allAuditTrailEntry)
                    {
                        string activityID = auditTrailEntryNode.SelectSingleNode("./m:WorkflowModelElement", nsmanager).InnerText;
                        DateTime startTM = DateTime.Parse(auditTrailEntryNode.SelectSingleNode("./m:Timestamp", nsmanager).InnerText);
                        string orginator = auditTrailEntryNode.SelectSingleNode("./m:Originator", nsmanager).InnerText;
                        string role = auditTrailEntryNode.SelectSingleNode("./m:Role", nsmanager).InnerText;
                        
                        if ( !m_allRples.Contains(role) )
                            m_allRples.Add(role);

                        XmlNodeList inputList = auditTrailEntryNode.SelectNodes("./m:Input", nsmanager);
                        List<InputPair> input = new List<InputPair>();
                        foreach (XmlNode inputlistNode in inputList)
                        {
                            string inputValue = inputlistNode.InnerText;
                            string inputOrginator = inputlistNode.Attributes["Originator"].InnerText;
                            input.Add(new InputPair(inputValue, inputOrginator));
                        }
                        DateTime completeTM = DateTime.Parse(auditTrailEntryNode.SelectSingleNode("./m:Timestamp", nsmanager).InnerText);
                        XmlNodeList outputList = auditTrailEntryNode.SelectNodes("./m:Output", nsmanager);
                        List<string> output = new List<string>();
                        foreach (XmlNode outputListNode in outputList)
                        {
                            string outputValue = outputListNode.InnerText;
                            output.Add(outputValue);
                        }

                        LogEntry entryToAdd = new LogEntry(processID, processInstanceID, activityID, orginator,role,startTM, input, completeTM, output);
                        currentTrace.AddLogEntry(entryToAdd);
                        
                    }
                    currentProcess.AddTrace(processInstanceID, currentTrace);
                }
                collection.AddProcess(processID, currentProcess);
            }
            
            return collection;
        }

        public bool ValidateXML(string fname)
        {
            Isvalid = true;
            StopLoop = false;
            //XmlReaderSettings settings = new XmlReaderSettings();
            //settings.Schemas.Add("XSDMXML", @"C:\Users\Soulaiman\Desktop\project files\RaDow\demo\NewLog.xsd");
            //settings.ValidationType = ValidationType.Schema;

            //XmlReader reader = XmlReader.Create(@"C:\Users\Soulaiman\Desktop\project files\RaDow\demo\pm2.xml", settings);
            //XmlDocument document = new XmlDocument();
            //document.Load(reader);

            //ValidationEventHandler eventHandler = new ValidationEventHandler(ValidationEventHandler);

            //document.Validate(eventHandler);
            //return Isvalid;
            XmlTextReader tr = new XmlTextReader(fname);
            XmlValidatingReader vr = new XmlValidatingReader(tr);

            vr.ValidationType = ValidationType.Schema;
            vr.ValidationEventHandler += new ValidationEventHandler(ValidationHandler);

            while (vr.Read() && !StopLoop)
            {
                
                if (vr.NodeType == XmlNodeType.Element)
                {
                    while (vr.MoveToNextAttribute())
                    { /*do nothing*/}
                   
                }

            }
            return Isvalid;

        }

        public void ValidationHandler(Object sender, ValidationEventArgs args)
        {
            Isvalid = false;
            StopLoop = true;
        }



        
    }
}